home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / mac / ZIPPED / DOS / GRAPHICS / R386DEV4.ZIP / KEYBOARD.C < prev    next >
C/C++ Source or Header  |  1992-09-27  |  29KB  |  1,308 lines

  1. /* Keyboard routines */
  2.  
  3. /* Written by Bernie Roehl, July 1992 */
  4.  
  5. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  6.    May be freely used to write software for release into the public domain;
  7.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  8.    for permission to incorporate any part of this software into their
  9.    products!
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <dos.h>
  14. #include <time.h>    /* time(), ctime() */
  15. #include <string.h>
  16. #include <math.h>
  17.  
  18. #include "include/rend386.h"
  19. #include "include/intmath.h"
  20. #include "include/plg.h"
  21. #include "include/pointer.h"
  22. #include "include/userint.h"
  23. #include "include/splits.h"
  24. #include "include/cursor.h"
  25.  
  26. extern STEREO default_stereo;
  27. extern manip_2D_avail;
  28.  
  29. extern int sl_xflip, sl_xoff;
  30. extern long sl_left, sl_top, sl_right, sl_bottom;
  31. extern int sr_xflip, sr_xoff;
  32. extern long sr_left, sr_top, sr_right, sr_bottom;
  33. extern float sl_xrot, sr_xrot;
  34.  
  35. int use_old_keys = 0;
  36. extern long latitude,longitude,center_roll;
  37. extern long center_x,center_y,center_z,center_d;
  38.  
  39. extern char *progname;
  40.  
  41. extern OBJECT *where_split_screen_pt(int *pol, int *vert, int x, int y);
  42.  
  43. extern int redraw, review, reframe, running, do_horizon;
  44. extern OBJLIST *objlist;
  45. extern long spacestep;
  46. extern int stereo_type;
  47. extern int fancy_background, reflection_pool, show_logo, do_screen_clear;
  48. extern VIEW default_view, orig_view, *current_view;
  49. extern STEREO default_stereo;
  50. extern SPLIT *split_tree;
  51. extern unsigned lastkey, nextolastkey;
  52. extern unsigned paint;
  53. extern int show_location, show_compass, show_framerate;
  54.  
  55. #define to_rad(a) ((a) * 3.14159262 / 180.0)
  56. #define sine(x)   sin(to_rad(x/65536L))
  57. #define cosine(x) cos(to_rad(x/65536L))
  58.  
  59. #define F1  0x3B00
  60. #define F2  0x3C00
  61. #define F3  0x3D00
  62. #define F4  0x3E00
  63. #define F5  0x3F00
  64. #define F6  0x4000
  65. #define F7  0x4100
  66. #define F8  0x4200
  67. #define F9  0x4300
  68. #define F10 0x4400
  69.  
  70. #define HOME      0x4700
  71. #define END       0x4F00
  72. #define PGUP      0x4900
  73. #define PGDN      0x5100
  74. #define LEFT      0x4B00
  75. #define RIGHT     0x4D00
  76. #define UP        0x4800
  77. #define DOWN      0x5000
  78. #define SHLEFT    0x4B01
  79. #define SHRIGHT   0x4D01
  80. #define SHUP      0x4801
  81. #define SHDOWN    0x5001
  82. #define SHPGUP    0x4901
  83. #define SHPGDN    0x5101
  84. #define CTRLLEFT  0x7300
  85. #define CTRLRIGHT 0x7400
  86. #define CTRLHOME  0x7700
  87. #define CTRLEND   0x7500
  88. #define CTRLPGUP  0x8400
  89. #define CTRLPGDN  0x7600
  90. #define ESC       0x001B
  91.  
  92. unsigned getkey()
  93. {
  94.     unsigned c;
  95.     union REGS regs;
  96.     int shifted;
  97.  
  98.     regs.h.ah = 2;
  99.     int86(0x16, ®s, ®s);
  100.     shifted = (regs.h.al & 3);
  101.     if ((c = bioskey(0)) & 0xFF) c &= 0xFF;
  102.     else if (shifted) c |= 1;
  103.     return c;
  104. }
  105.  
  106. char *helptext[] = {
  107.     "              HELP",
  108.     "ARROWS       move around horizonally",
  109.     "Pgup/Pgdn    move up/down",
  110.     "CTRL+ARROWS  twist head, U u-turns",
  111.     "CTRL PgUp/CTRL PgDn tilt head up/down",
  112.     "+ and - keys zoom in and out",
  113.     "G go to specified x,y,z location",
  114.     "R repeats last move 100x",
  115.     "I gives information  O sets options",
  116.     "0-9 set step size (0 = 10)",
  117.     "* resets to default view",
  118.     "Q quits, ? shows help",
  119.     "V resizes view, ^ saves PCX file",
  120.     "C changes hither/yon clipping",
  121.     "D displays status information",
  122.     "L loads, S saves PLG files",
  123.     "M loads multi-resolution PLG files",
  124.     "F loads figure files",
  125.     "P displays color palette",
  126.     "Z does object manipulation",
  127.     "X invokes extra features",
  128.     NULL
  129. };
  130.  
  131. static char *featmenu[] = {
  132.     "Select Surface type",
  133.     "Choose Color",
  134.     "Paint Polys",
  135.     NULL
  136. };
  137.  
  138. static char *surfmenu[] = {
  139.     "Absolute",
  140.     "Cosine-lit",
  141.     "Metal",
  142.     "Glass",
  143.     NULL
  144. };
  145.  
  146. void disp_palette()
  147. {
  148.     int i, j, page;
  149.     page = cursor_hide();
  150.     for (i = 0; i < 16; i++)
  151.         for (j = 0; j < 16; j++)
  152.             user_box(j*10,i*8,j*10+9,i*8+8,i*16+j);
  153.     cursor_show(page);
  154.     reframe = 1;
  155. }
  156.  
  157. static int stepsize = 5;
  158.  
  159. static long anglestep = 2L * 65536L;
  160.  
  161. FILE *save_file = NULL;
  162.  
  163. int nsaved = 0;
  164.  
  165. void save_it(OBJECT *obj)
  166. {
  167.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  168.     {
  169.         char buff[100];
  170.         save_plg(obj, save_file);
  171.         sprintf(buff, "%d object%s saved", ++nsaved,
  172.         (nsaved > 1) ? "s" : "");
  173.         refresh_display();
  174.         popmsg(buff);
  175.         reframe = 1;
  176.     }
  177. }
  178.  
  179. do_key(unsigned c)
  180. {
  181.     void joystick_calibration(), *what_area();
  182.     char buff[100];
  183.     FILE *in, *out;
  184.     long x, y, z;
  185.     int i, j;
  186.     MATRIX m,n;
  187.     long av, bv, cv, dv; /* used for 'A' */
  188.     if (check_key(c)) return 0;
  189.     switch (c)
  190.     {
  191. #ifdef NFF_SAVE   /* not in this release... */
  192.     case 'N':
  193.     case 'n':
  194.         nextolastkey = 0;
  195.         askfor("File to save? ", buff, 15);
  196.         if (buff[0] == '\0') {
  197.             redraw = 1;
  198.             break;
  199.         }
  200.         if ((out = fopen(buff, "w")) == NULL) {
  201.             popmsg("Could not save file");
  202.             getkey();
  203.         }
  204.         else {
  205.             save_nff(out);
  206.             fclose(out);
  207.         }
  208.         reframe = redraw = 1;
  209.         break;
  210. #endif
  211.     case 'M':
  212.     case 'm':
  213.         nextolastkey = 0;
  214.         askfor("File to load? ", buff, 15);
  215.         if (buff[0] == '\0') {
  216.             redraw = 1;
  217.             break;
  218.         }
  219.         if ((in = fopen(buff, "r")) == NULL) {
  220.             popmsg("Could not load file");
  221.             getkey();
  222.         }
  223.         else {
  224.             OBJECT *obj;
  225.             SEGMENT *s;
  226.             set_loadplg_offset(0,0,0);
  227.             set_loadplg_scale(1,1,1);
  228.             obj = load_multi_plg(in);
  229.             select_representation(obj, 0L);
  230.             add_obj_to_split_area(split_tree, obj);
  231.             if ((s = new_seg(NULL)) == NULL) {
  232.                 popmsg("Warning -- out of memory!");
  233.                 getkey();
  234.             }
  235.             else {
  236.                 seg_set_object(s, obj);
  237.                 set_object_owner(obj, s);
  238.                 update_segment(s);
  239.             }
  240.             if (spacestep < get_object_bounds(obj, &x, &y, &z)/5L)
  241.                 spacestep = get_object_bounds(obj, &x, &y, &z)/5L;
  242.             fclose(in);
  243.         }
  244.         reframe = redraw = 1;
  245.         break;
  246.     case 'G':
  247.     case 'g':
  248.         nextolastkey = 0;
  249.         askfor("X,Y,Z: ", buff, 15);
  250.         if (buff[0])
  251.             sscanf(buff, "%ld,%ld,%ld", ¤t_view->ex, ¤t_view->ey, ¤t_view->ez);
  252.         reframe = review = redraw = 1;
  253.         break;
  254.     case LEFT:
  255.         if (use_old_keys)
  256.             latitude -= stepsize * anglestep;
  257.         else
  258.             current_view->pan -= stepsize * anglestep;
  259.         review = redraw = 1;
  260.         break;
  261.     case RIGHT:
  262.         if (use_old_keys)
  263.             latitude += stepsize * anglestep;
  264.         else
  265.             current_view->pan += stepsize * anglestep;
  266.         longitude -= stepsize * anglestep;
  267.         review = redraw = 1;
  268.         break;
  269.     case UP:
  270.         if (use_old_keys)
  271.             longitude += stepsize * anglestep;
  272.         else
  273.             {
  274.             current_view->ex += (stepsize * spacestep) * sine(current_view->pan);
  275.             current_view->ez += (stepsize * spacestep) * cosine(current_view->pan);
  276.         }
  277.         review = redraw = 1;
  278.         break;
  279.     case DOWN:
  280.         if (use_old_keys)
  281.             longitude -= stepsize * anglestep;
  282.         else
  283.             {
  284.             current_view->ex -= (stepsize * spacestep) * sine(current_view->pan);
  285.             current_view->ez -= (stepsize * spacestep) * cosine(current_view->pan);
  286.         }
  287.         review = redraw = 1;
  288.         break;
  289.     case PGUP:
  290.         if (use_old_keys)
  291.             center_d += (stepsize * spacestep);
  292.         else
  293.             current_view->tilt += (stepsize * anglestep);
  294.         review = redraw = 1;
  295.         break;
  296.     case PGDN:
  297.         if (use_old_keys)
  298.             center_d -= (stepsize * spacestep);
  299.         else
  300.             current_view->tilt -= (stepsize * anglestep);
  301.         review = redraw = 1;
  302.         break;
  303.     case CTRLLEFT:
  304.         if (use_old_keys)
  305.             center_roll -= stepsize * anglestep;
  306.         else
  307.             {
  308.             current_view->ex -= (stepsize * spacestep) * cosine(current_view->pan);
  309.             current_view->ez += (stepsize * spacestep) * sine(current_view->pan);
  310.         }
  311.         review = redraw = 1;
  312.         break;
  313.     case CTRLRIGHT:
  314.         if (use_old_keys)
  315.             center_roll += stepsize * anglestep;
  316.         else
  317.             {
  318.             current_view->ex += (stepsize * spacestep) * cosine(current_view->pan);
  319.             current_view->ez -= (stepsize * spacestep) * sine(current_view->pan);
  320.         }
  321.         review = redraw = 1;
  322.         break;
  323.     case CTRLPGUP:
  324.         if (use_old_keys)
  325.             current_view->zoom += stepsize * 65536L/10;
  326.         else
  327.             current_view->ey += (stepsize * spacestep);
  328.         review = redraw = 1;
  329.         break;
  330.     case CTRLPGDN:
  331.         if (use_old_keys)
  332.             current_view->zoom -= stepsize * 65536L/10;
  333.         else
  334.             current_view->ey -= (stepsize * spacestep);
  335.         review = redraw = 1;
  336.         break;
  337.     case CTRLHOME:
  338.         current_view->roll -= (stepsize * anglestep);
  339.         review = redraw = 1;
  340.         break;
  341.     case CTRLEND:
  342.         current_view->roll += (stepsize * anglestep);
  343.         review = redraw = 1;
  344.         break;
  345.     case '+':
  346.         if (stereo_type == MONOSCOPIC)
  347.             current_view->zoom *= 1.1;
  348.         else
  349.             default_stereo.world_scaling *= 1.1;
  350.         review = redraw = 1;
  351.         break;
  352.     case '-':
  353.         if (stereo_type == MONOSCOPIC)
  354.             current_view->zoom /= 1.1;
  355.         else {
  356.             default_stereo.world_scaling /= 1.1;
  357.             if (default_stereo.world_scaling <= 10)
  358.                 default_stereo.world_scaling = 11;
  359.         }
  360.         review = redraw = 1;
  361.         break;
  362.     case 'U':
  363.     case 'u':
  364.         current_view->pan += 180*65536L;
  365.         nextolastkey = 0;
  366.         review = redraw = 1;
  367.         break;
  368.     case '*':
  369.         nextolastkey = 0;
  370.         if (use_old_keys)
  371.         {
  372.             current_view = &default_view;
  373.             center_d = 10000;
  374.             center_x = 0;
  375.             center_y = 0;
  376.             center_z = 0;
  377.             latitude = 0;
  378.             longitude = 0;
  379.             center_roll = 0;
  380.         }
  381.         else
  382.             default_view = orig_view;
  383.         review = redraw = 1;
  384.         break;
  385.     case SHLEFT:
  386.         x = stepsize*spacestep/10;
  387.         y = 0;
  388.         review = redraw = 1;
  389.         goto fixcenter;  /* save some code (Dave) */
  390.     case SHRIGHT:
  391.         x = -stepsize*spacestep/10 ;
  392.         y = 0;
  393.         review = redraw = 1;
  394.         goto fixcenter;  /* save some code (Dave) */
  395.     case SHUP:
  396.         y = -stepsize*spacestep/10;
  397.         x = 0;
  398.         review = redraw = 1;
  399.         goto fixcenter;  /* save some code (Dave) */
  400.     case SHDOWN:
  401.         y = stepsize*spacestep/10;
  402.         x = 0;
  403.         review = redraw = 1;
  404. fixcenter:
  405.         z = 0;
  406.         std_matrix(n,longitude,latitude,center_roll,0,0,0);
  407.         matrix_point(n,&x,&y,&z);
  408.         center_x += x;
  409.         center_y += y;
  410.         center_d -= z;
  411.         break;
  412.     case SHPGUP:
  413.         center_z += stepsize*spacestep/10;
  414.         review = redraw = 1;
  415.         break;
  416.     case SHPGDN:
  417.         center_z -= stepsize*spacestep/10;
  418.         review = redraw = 1;
  419.         break;
  420.     case '[':
  421.         nextolastkey = 0;
  422.         if (sl_xflip) sl_xoff++; else sl_xoff--;
  423.         if (sr_xflip) sr_xoff--; else sr_xoff++;
  424.         review = redraw = 1;
  425.         goto stereo_recompute;  /* save some code (Dave) */
  426.     case ']':
  427.         nextolastkey = 0;
  428.         if (sl_xflip) sl_xoff--; else sl_xoff++;
  429.         if (sr_xflip) sr_xoff++; else sr_xoff--;
  430.         review = redraw = 1;
  431.         goto stereo_recompute;  /* save some code (Dave) */
  432.     case '{':
  433.         nextolastkey = 0;
  434.         default_stereo.phys_screen_width++;
  435.         review = redraw = 1;
  436.         goto stereo_recompute;  /* save some code (Dave) */
  437.     case '}':
  438.         nextolastkey = 0;
  439.         default_stereo.phys_screen_width--;
  440.         review = redraw = 1;
  441. stereo_recompute:
  442.         if (stereo_type != MONOSCOPIC)
  443.         {
  444.             compute_stereo_data(&default_stereo, LEFT_EYE, sl_xflip, sl_xoff, 65536.0*sl_xrot,
  445.                 sl_left, sl_top, sl_right, sl_bottom);
  446.  
  447.             compute_stereo_data(&default_stereo, RIGHT_EYE, sr_xflip, sr_xoff, 65536.0*sr_xrot,
  448.                 sr_left, sr_top, sr_right, sr_bottom);
  449.         }
  450.         break;
  451.  
  452.     case '0':
  453.         nextolastkey = 0;
  454.         stepsize = 10;
  455.         break;
  456.     case '1': case '2': case '3': case '4': case '5':
  457.     case '6': case '7': case '8': case '9':
  458.         nextolastkey = 0;
  459.         stepsize = c - '0';
  460.         break;
  461.     case 'Q':
  462.     case 'q':
  463.     case ESC:
  464.         nextolastkey = 0;
  465.         popmsg("Really quit?");
  466.         if (toupper(getkey()) == 'Y') running = 0; 
  467.         else reframe = redraw = 1;
  468.         break;
  469.     case 'R':
  470.     case 'r':
  471.         nextolastkey = lastkey;
  472.         if (lastkey)
  473.             for (i = 0; i < 100; i++) {
  474.                 do_key(lastkey);
  475.                 refresh_display();
  476.             }
  477.         break;
  478.     case 'C':
  479.     case 'c':
  480.         nextolastkey = 0;
  481.         popmsg("Change Hither or Yon?");
  482.         switch (toupper(getkey()))
  483.         {
  484.         case 'H':
  485.             askfor("Enter hither value:", buff, 10);
  486.             if (buff[0])
  487.                 current_view->hither = atof(buff);
  488.             if (current_view->hither < 1) current_view->hither = 1;
  489.             review = 1;
  490.             break;
  491.         case 'Y':
  492.             askfor("Enter yon value:", buff, 10);
  493.             if (buff[0]) current_view->yon = atof(buff);
  494.             review = 1;
  495.             break;
  496.         default:
  497.             break;
  498.         }
  499.         reframe = redraw = 1;
  500.         break;
  501.     case 'D':
  502.     case 'd':
  503.         nextolastkey = 0;
  504.         disp_status(current_view);
  505.         reframe = redraw = 1;
  506.         break;
  507.     case 'L':
  508.     case 'l':
  509.         nextolastkey = 0;
  510.         askfor("File to load? ", buff, 15);
  511.         if (buff[0] == '\0') {
  512.             redraw = 1;
  513.             break;
  514.         }
  515.         if ((in = fopen(buff, "r")) == NULL) {
  516.             popmsg("Could not load file");
  517.             getkey();
  518.         }
  519.         else {
  520.             OBJECT *obj;
  521.             set_loadplg_offset(0,0,0);
  522.             set_loadplg_scale(1,1,1);
  523.             while ((obj = load_plg(in)) != NULL) {
  524.                 SEGMENT *s;
  525.                 add_obj_to_split_area(split_tree, obj);
  526.                 if ((s = new_seg(NULL)) == NULL) {
  527.                     popmsg("Warning -- out of memory!");
  528.                     getkey();
  529.                 }
  530.                 else {
  531.                     seg_set_object(s, obj);
  532.                     set_object_owner(obj, s);
  533.                     update_segment(s);
  534.                 }
  535.                 /*                    if (spacestep < get_object_bounds(obj, &x, &y, &z)/5L)
  536.                                                                                         spacestep = get_object_bounds(obj, &x, &y, &z)/5L; */
  537.             }
  538.             fclose(in);
  539.         }
  540.         reframe = redraw = 1;
  541.         break;
  542.     case 'S':
  543.     case 's':
  544.         nextolastkey = 0;
  545.         askfor("File to save? ", buff, 15);
  546.         if (buff[0] == '\0') {
  547.             redraw = 1;
  548.             break;
  549.         }
  550.         if ((save_file = fopen(buff, "w")) == NULL) {
  551.             popmsg("Could not open file");
  552.             getkey();
  553.         }
  554.         else {
  555.             nsaved = 0;
  556.             walk_split_tree(split_tree, save_it);
  557.             fclose(save_file);
  558.         }
  559.         reframe = redraw = 1;
  560.         break;
  561.     case 'Z':
  562.     case 'z':
  563.         nextolastkey = 0;
  564.         advanced();
  565.         while (bioskey(1)) bioskey(0); /* flush keyboard buffer */
  566.         reframe = redraw = 1; 
  567.         break;
  568.     case 'I':
  569.     case 'i':
  570.         nextolastkey = 0;
  571.         disp_info(); 
  572.         reframe = redraw = 1; 
  573.         break;
  574.     case 'P':
  575.     case 'p':
  576.         nextolastkey = 0; 
  577.         disp_palette();
  578.         getkey(); 
  579.         reframe = redraw = 1;
  580.         break;
  581.     case 'F':
  582.     case 'f':
  583.         nextolastkey = 0;
  584.         askfor("Figure file to read? ", buff, 15);
  585.         if (buff[0] == '\0') {
  586.             reframe = redraw = 1;
  587.             break;
  588.         }
  589.         if ((in = fopen(buff, "r")) == NULL) {
  590.             popmsg("Could not load figure file");
  591.             getkey();
  592.         }
  593.         else {
  594.             SEGMENT *s, *readseg();
  595.             int c;
  596.             while ((c = getc(in)) != '{')
  597.                 if (c == EOF) {
  598.                     popmsg("Early EOF!");
  599.                     getkey();
  600.                     break;
  601.                 }
  602.             set_readseg_objlist(objlist);
  603.             if ((s = readseg(in, NULL)) == NULL) {
  604.                 popmsg("Error reading figure file");
  605.                 getkey();
  606.             }
  607.             else
  608.                 update_segment(s);
  609.         }
  610.         reframe = redraw = 1;
  611.         break;
  612.     case 'H':
  613.     case 'h':
  614.     case '?':
  615.         nextolastkey = 0;
  616.         poptext(helptext);
  617.         getkey();
  618.         reframe = redraw = 1;
  619.         break;
  620.     case 'O':
  621.     case 'o':
  622.         nextolastkey = 0;
  623.         set_options();
  624.         reframe = redraw = 1;
  625.         break;
  626. #ifdef RESIZE_IMPLEMENTED
  627.     case 'V':
  628.     case 'v':
  629.         nextolastkey = 0;
  630.         resize_viewport();
  631.         reframe = review = redraw = 1;
  632.         break;
  633. #endif
  634.     case 'X':
  635.     case 'x':
  636.         nextolastkey = 0;
  637.         new_features();
  638.         while (bioskey(1)) bioskey(0); /* flush keyboard buffer */
  639.         reframe = review = redraw = 1;
  640.         break;
  641.     case '^':
  642.         nextolastkey = 0;
  643.         save_pcx_file();
  644.     default:
  645.         break;
  646.     }
  647.     return 0;
  648. }
  649.  
  650. extern long last_render_time;
  651.  
  652. do_joy(joystick_data *joy)
  653. {
  654.     long dist = spacestep*stepsize;
  655.     float cosvalue, sinvalue;
  656.     int x = joy->x;
  657.     int y = joy->y;
  658.     int sscale = last_render_time;
  659.  
  660.     if (abs(x) < 10 && abs(y) < 10) return 0;
  661.  
  662.     if (x > 10) x -= 10; 
  663.     else
  664.     {
  665.         if (x > -10) x = 0;
  666.         else x += 10;
  667.     }
  668.     if (y > 10) y -= 10;
  669.     else
  670.     {
  671.         if (y > -10) y = 0;
  672.         else y += 10;
  673.     }
  674.     cosvalue = cosine(current_view->pan);
  675.     sinvalue = sine(current_view->pan);
  676.     switch (joy->buttons)
  677.     {
  678.     case 0:/* no buttons down */
  679.         current_view->pan += (x * anglestep*stepsize)/1200*sscale;
  680.         current_view->ex -= (y * dist * sinvalue)/100*sscale ;
  681.         current_view->ez -= (y * dist * cosvalue)/100*sscale ;
  682.         review = redraw = 1;
  683.         break;
  684.     case 1:/* first button down */
  685.         current_view->tilt -= (y * anglestep*stepsize)/2000*sscale;
  686.         current_view->ex -= (x * dist * cosvalue)/400*sscale ;
  687.         current_view->ez += (x * dist * sinvalue)/400*sscale ;
  688.         review = redraw = 1;
  689.         break;
  690.     case 2:/* second button down */
  691.         current_view->ex -= (x * dist * cosvalue)/400*sscale ;
  692.         current_view->ez += (x * dist * sinvalue)/400*sscale ;
  693.         current_view->ey -= (y * spacestep*stepsize)/400*sscale ;
  694.         review = redraw = 1;
  695.         break;
  696.     case 3:/* both buttons down */
  697.         current_view->roll += (x * anglestep*stepsize)/400*sscale;
  698.         current_view->zoom += (y*65536L) /4000*sscale;
  699.         review = redraw = 1;
  700.         break;
  701.     default:
  702.         break;
  703.     }
  704.     return 0;
  705. }
  706.  
  707. static char *adv_menu[] = {
  708.     "Move",
  709.     "Rotate",
  710.     "Twirl",
  711.     "Alter",
  712.     "Paint",
  713.     "Info",
  714.     "Save",
  715.     "Delete",
  716.     "Unselect",
  717.     "Hack off",
  718.     "Join to",
  719.     "Figure...",
  720.     "Next rep",
  721.     NULL
  722. };
  723.  
  724. POINTER pointer;
  725.  
  726. static char *surface_menu[] = { 
  727.     "Normal", "Cosine-lit", "Metal", "Glass", NULL };
  728.  
  729. static char *figure_menu[] = {
  730.     "Figure select",
  731.     "Delete",
  732.     "Save",
  733.     "Copy",
  734.     "Info",
  735.     NULL
  736. };
  737.  
  738. void select_tree(SEGMENT *s)
  739. {
  740.     SEGMENT *p; 
  741.     OBJECT *obj;
  742.     if ((obj = seg_get_object(s)) != NULL) highlight_obj(obj);
  743.     for (p = child_segment(s); p; p = sibling_segment(p))
  744.         select_tree(p);
  745. }
  746.  
  747. void count_tree(SEGMENT *s, int *nsegs, int *nverts, int *npolys)
  748. {
  749.     SEGMENT *p;
  750.     OBJECT *obj;
  751.     ++*nsegs;
  752.     if ((obj = seg_get_object(s)) != NULL) {
  753.         int nv, np;
  754.         get_obj_info(obj, &nv, &np);
  755.         *nverts += nv; 
  756.         *npolys += np;
  757.     }
  758.     for (p = child_segment(s); p; p = sibling_segment(p))
  759.         count_tree(p, nsegs, nverts, npolys);
  760. }
  761.  
  762. static void zap_obj(OBJECT *obj)
  763. {
  764.     remove_from_objlist(obj);
  765.     delete_obj(obj);
  766. }
  767.  
  768. int nselected = 0;
  769.  
  770. void count_selected(OBJECT *obj)
  771. {
  772.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  773.         ++nselected;
  774. }
  775.  
  776. int nobjs = 0, nverts = 0, npolys = 0;
  777.  
  778. void gather_info(OBJECT *obj)
  779. {
  780.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  781.     {
  782.         int nv, np;
  783.         ++nobjs;
  784.         get_obj_info(obj, &nv, &np);
  785.         nverts += nv;
  786.         npolys += np;
  787.     }
  788. }
  789.  
  790. long ptx, pty, ptz;
  791.  
  792. long oldx, oldy, oldz, oldcx, oldcy, oldcz, dx, dy, dz;
  793.  
  794.  
  795. void move_it(OBJECT *obj)
  796. {
  797.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  798.     {
  799.         SEGMENT *s;
  800.         if ((s = get_object_owner(obj)) != NULL)
  801.         {
  802.             rel_move_segment(s, ptx - oldx, pty - oldy, ptz - oldz);
  803.             update_segment(s);
  804.         }
  805.     }
  806. }
  807.  
  808. void rot_it(OBJECT *obj)
  809. {
  810.     int i;
  811.  
  812.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  813.     {
  814.         SEGMENT *s;
  815.         if ((s = get_object_owner(obj)) != NULL)
  816.         {
  817.             rel_rot_segment(s, ptx, pty, ptz, RYXZ);
  818.             update_segment(s);
  819.         }
  820.     }
  821. }
  822.  
  823. unsigned surf;
  824.  
  825. void surf_it(OBJECT *obj)
  826. {
  827.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  828.         int nv, np, i;
  829.         get_obj_info(obj, &nv, &np);
  830.         for (i = 0; i < np; ++i) {
  831.             unsigned color;
  832.             get_poly_info(obj, i, &color, &nv, NULL, 0);
  833.             set_poly_color(obj, i, (color & 0xCFFF) | surf);
  834.         }
  835.     }
  836. }
  837.  
  838. void color_it(OBJECT *obj)
  839. {
  840.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  841.         int nv, np, i;
  842.         get_obj_info(obj, &nv, &np);
  843.         for (i = 0; i < np; ++i)
  844.             set_poly_color(obj, i, 0x8000 | paint);
  845.     }
  846. }
  847.  
  848. void unhi_it(OBJECT *obj)
  849. {
  850.     set_obj_flags(obj, get_obj_flags(obj) & ~OBJ_HIGHLIGHTED);
  851.     unhighlight_obj(obj);
  852. }
  853.  
  854. void hack_it(OBJECT *obj)
  855. {
  856.     SEGMENT *s;
  857.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL) {
  858.         detach_segment(s);
  859.         update_segment(s);
  860.     }
  861. }
  862.  
  863. SEGMENT *newparent = NULL;
  864.  
  865. void join_it(OBJECT *obj)
  866. {
  867.     SEGMENT *s;
  868.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) &&
  869.         (s = get_object_owner(obj)) != NULL)
  870.     {
  871.         attach_segment(s, newparent);
  872.         update_segment(s);
  873.     }
  874. }
  875.  
  876. void nuke_it(OBJECT *obj)
  877. {
  878.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED)) {
  879.         SEGMENT *s;
  880.         if ((s = get_object_owner(obj)) != NULL)
  881.             seg_set_object(s, NULL);
  882.         remove_from_objlist(obj);
  883.         delete_obj(obj);
  884.     }
  885. }
  886.  
  887. void next_it(OBJECT *obj)
  888. {
  889.     next_rep(obj);
  890. }
  891.  
  892. extern PDRIVER *cursor_device;
  893.  
  894. advanced()
  895. {
  896.     SEGMENT *s;
  897.     OBJECT *obj;
  898.     void pointer_to_world();
  899.     int nsegs = 0;
  900.     char buff[100], *p;
  901.     FILE *out;
  902.     char c, d;
  903.     unsigned char oldflags;
  904.     int mx, my;
  905.     unsigned buttons;
  906.     time_t now;
  907.     int click = 0;
  908.  
  909.     init_pointer(&pointer);
  910.  
  911.     nselected = 0;
  912.     walk_split_tree(split_tree, count_selected);
  913.     if (nselected == 0)
  914.     {
  915.         popmsg("No objects selected!");
  916.         delay(600);
  917.         return 0;
  918.     }
  919.  
  920.     poptext(adv_menu);
  921.     switch (c = toupper(getkey()))
  922.     {
  923.     case 'N':
  924.         walk_split_tree(split_tree, next_it);
  925.         break;
  926.     case 'S':
  927.         refresh_display();
  928.         if (askfor("Enter filename: ", buff, 20) == 0x1B) break;
  929.         if (buff[0] == '\0') {
  930.             reframe = redraw = 1;
  931.             break;
  932.         }
  933.         nobjs = 0;
  934.         if ((save_file = fopen(buff, "w")) == NULL)
  935.         {
  936.             popmsg("Could not create file");
  937.             reframe = 1;
  938.             getkey();
  939.             break;
  940.         }
  941.         nsaved = 0;
  942.         walk_split_tree(split_tree, save_it);
  943.         fclose(save_file);
  944.         save_file = NULL;
  945.         refresh_display();
  946.         sprintf(buff, "Saved %d object%s", nobjs, (nobjs > 1) ? "s" : "");
  947.         popmsg(buff);
  948.         getkey();
  949.         fclose(out);
  950.         break;
  951.     case 'I':
  952.         refresh_display();
  953.         nobjs = nverts = npolys = 0;
  954.         walk_split_tree(split_tree, gather_info);
  955.         sprintf(buff, "%d obj%s, %d vertice%s, %d polygon%s", nobjs, (nobjs == 1) ? "" : "s", nverts, (nverts == 1) ? "" : "s", npolys, (npolys == 1) ? "" : "s");
  956.         popmsg(buff);
  957.         getkey();
  958.         break;
  959.  
  960.     case 'M':
  961.         refresh_display();
  962.         if (!manip_2D_avail) break;
  963.         pointer_read(cursor_device, &pointer);
  964.         pointer_to_world(&pointer, current_view, &ptx, &pty, &ptz);
  965.         click = 0;
  966.         while (click == 0)
  967.         {
  968.             refresh_display();
  969.             oldx = ptx;
  970.             oldy = pty;
  971.             oldz = ptz;
  972.             click = PNEW_BUT & pointer_read(cursor_device, &pointer);
  973.             if (!(pointer.buttons & 1)) click = 0;
  974.             pointer_to_world(&pointer, current_view, &ptx, &pty, &ptz);
  975.             walk_split_tree(split_tree, move_it);
  976.         }
  977.         refresh_display();
  978.         break;
  979.     case 'R':
  980.     case 'T':
  981.         refresh_display();
  982.         if (!manip_2D_avail) break;
  983.         pointer_read(cursor_device, &pointer);
  984.         oldcx = oldx = pointer.x;
  985.         oldcy = oldy = pointer.y;
  986.         oldcz = oldz = pointer.z;
  987.         while ((pointer.buttons & 0x01) == 0)
  988.         {
  989.             if (c == 'R')
  990.             {
  991.                 ptx = 32768L*(pointer.y - oldy);
  992.                 pty = -32768L*(pointer.x - oldx);
  993.                 ptz = -32768L*(pointer.z - oldz);
  994.             }
  995.             else
  996.             {
  997.                 ptx = 3270L*(pointer.y - oldcy);
  998.                 pty = -3270L*(pointer.x - oldcx);
  999.                 ptz = -3270L*(pointer.z - oldcz);
  1000.             }
  1001.             rotate_to_view(current_view, &ptx, &pty, &ptz);
  1002.             walk_split_tree(split_tree, rot_it);
  1003.             oldx = pointer.x;
  1004.             oldy = pointer.y;
  1005.             oldz = pointer.z;
  1006.             refresh_display();
  1007.             pointer_read(cursor_device, &pointer);
  1008.         }
  1009.  
  1010.         while (pointer.buttons & 0x01) pointer_read(cursor_device, &pointer);
  1011.         refresh_display();
  1012.         break;
  1013.  
  1014.     case 'A':
  1015.         refresh_display();
  1016.         poptext(surface_menu);
  1017.         switch (toupper(getkey())) {
  1018.         case 'N':
  1019.             surf = 0x0000; 
  1020.             break;
  1021.         case 'C':
  1022.             surf = 0x1000; 
  1023.             break;
  1024.         case 'M':
  1025.             surf = 0x2000; 
  1026.             break;
  1027.         case 'G':
  1028.             surf = 0x3000;
  1029.             break;
  1030.         default:
  1031.             return 0;
  1032.         }
  1033.         walk_split_tree(split_tree, surf_it);
  1034.         refresh_display();
  1035.         break;
  1036.     case 'P':
  1037.         walk_split_tree(split_tree, color_it);
  1038.         refresh_display();
  1039.         break;
  1040.     case 'D':
  1041.         refresh_display();
  1042.         sprintf(buff, "Delete %d object%s!  Are you sure?", nselected, (nselected > 1) ? "s" : "");
  1043.         popmsg(buff);
  1044.         reframe = 1;
  1045.         if (toupper(getkey()) != 'Y') break;
  1046.         refresh_display();
  1047.         walk_split_tree(split_tree, nuke_it);
  1048.         refresh_display();
  1049.         break;
  1050.     case 'U':
  1051.         walk_split_tree(split_tree, unhi_it);
  1052.         refresh_display();
  1053.         break;
  1054.     case 'H':
  1055.         refresh_display();
  1056.         walk_split_tree(split_tree, hack_it);
  1057.         break;
  1058.     case 'J':
  1059.         if (!can_point_2D()) break;
  1060.         if (!manip_2D_avail) break;
  1061.         refresh_display();
  1062.         popmsg("Click on new parent");
  1063.         reframe = 1;
  1064.         refresh_display();
  1065.         newparent = NULL;
  1066.         do {
  1067.             OBJECT *newobj;
  1068.  
  1069.             move_till_click(cursor_device, 1, &mx, &my);
  1070.             newobj = where_split_screen_pt(NULL, NULL, mx, my);
  1071.             if (newobj)
  1072.                 if ((get_obj_flags(newobj) & OBJ_HIGHLIGHTED) == 0)
  1073.                     newparent = get_object_owner(newobj);
  1074.         }
  1075.         while (newparent == NULL);
  1076.         walk_split_tree(split_tree, join_it);
  1077.         break;
  1078.     case 'F':
  1079.         refresh_display();
  1080.         poptext(figure_menu);
  1081.         for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(obj))
  1082.             if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL)
  1083.                 break;
  1084.         if (obj == NULL || s == NULL) {
  1085.             popmsg("No objects selected!");
  1086.             getkey();
  1087.             return 0;
  1088.         }
  1089.         switch (toupper(getkey())) {
  1090.         case 'F':
  1091.             select_tree(find_root_segment(s)); /* and down again */
  1092.             break;
  1093.         case 'D':
  1094.             refresh_display();
  1095.             popmsg("Delete entire figure! Are you sure?");
  1096.             if (toupper(getkey()) != 'Y') break;
  1097.             refresh_display();
  1098.             delete_segment(find_root_segment(s), zap_obj);
  1099.             break;
  1100.         case 'I':
  1101.             count_tree(find_root_segment(s), &nsegs, &nverts, &npolys);
  1102.             sprintf(buff, "%d segs, %d verts, %d polys", nsegs, nverts, npolys);
  1103.             popmsg(buff);
  1104.             getkey();
  1105.             break;
  1106.         case 'S':
  1107.             refresh_display();
  1108.             askfor("Filename: ", buff, 20);
  1109.             if (buff[0] == '\0') break;
  1110.             refresh_display();
  1111.             if ((out = fopen(buff, "w")) == NULL) {
  1112.                 popmsg("Could not create file");
  1113.                 getkey();
  1114.                 break;
  1115.             }
  1116.             askfor("Comment: ", buff, 20);
  1117.             if ((p = strchr(buff, ';')) != NULL) *p = '\0';
  1118.             fprintf(out, "Comment = %s;\n", buff);
  1119.             time(&now);
  1120.             strcpy(buff, ctime(&now));
  1121.             if ((p = strchr(buff, '\n')) != NULL) *p = '\0';
  1122.             fprintf(out, "Comment = Saved from %s %s;\n", progname, buff);
  1123.             writeseg(out, find_root_segment(s), 0);
  1124.             fclose(out);
  1125.             break;
  1126.         default:
  1127.             return 0;
  1128.         }
  1129.         break;
  1130.     default:
  1131.         break;
  1132.     }
  1133.     return 0;
  1134. }
  1135.  
  1136. static char *optmenu[] = {
  1137.     "Background",
  1138.     "Reflection",
  1139.     "Logo",
  1140.     "Screen clear",
  1141.     "Ambient light",
  1142.     "Directional light",
  1143.     "Horizon",
  1144.     "Motion step size",
  1145.     "Keyboard mode",
  1146.     "Position display",
  1147.     "Compass display",
  1148.     "Frame rate display",
  1149.     NULL };
  1150.  
  1151. set_options()
  1152. {
  1153.     char buff[20];
  1154.     poptext(optmenu);
  1155.     switch (toupper(getkey())) {
  1156.     case 'B':
  1157.         fancy_background = !fancy_background; 
  1158.         break;
  1159.     case 'R':
  1160.         reflection_pool = !reflection_pool;
  1161.         current_view->bottom = reflection_pool ? 160 : 199;
  1162.         break;
  1163.     case 'L':
  1164.         show_logo = !show_logo; 
  1165.         if (!show_logo) reset_screens();
  1166.         break;
  1167.     case 'S':
  1168.         do_screen_clear = !do_screen_clear;
  1169.         popmsg(do_screen_clear ? "Will clear" : "Won't clear");
  1170.         delay(600);
  1171.         break;
  1172.     case 'D':
  1173.         current_view->directional = !current_view->directional;
  1174.         popmsg(current_view->directional ? "Spotlight" : "Point Source");
  1175.         delay(600);
  1176.         break;
  1177.     case 'H':
  1178.         do_horizon = !do_horizon;
  1179.         if (!do_horizon) reset_screens();
  1180.         popmsg(do_horizon ? "Horizon" : "No Horizon");
  1181.         delay(600);
  1182.         break;
  1183.     case 'A':
  1184.         askfor("Ambient light: ", buff, 15);
  1185.         current_view->ambient = atoi(buff) & 0xFF;
  1186.         break;
  1187.     case 'M':
  1188.         popmsg("Space or Angle?");
  1189.         switch (toupper(getkey())) {
  1190.         case 'S':
  1191.             askfor("New space step: ", buff, 15);
  1192.             if (buff[0]) spacestep = atoi(buff);
  1193.             break;
  1194.         case 'A':
  1195.             askfor("New angle step: ", buff, 15);
  1196.             if (buff[0]) anglestep = atof(buff) * 65536L;
  1197.             break;
  1198.         default:
  1199.             break;
  1200.         }
  1201.         break;
  1202.     case 'K':
  1203.         use_old_keys = !use_old_keys;
  1204.         review = 1;
  1205.         break;
  1206.     case 'P':
  1207.         show_location = !show_location;
  1208.         if (!show_location) reset_screens();
  1209.         break;
  1210.     case 'C':
  1211.         show_compass = !show_compass;
  1212.         if (!show_compass) reset_screens();
  1213.         break;
  1214.     case 'F':
  1215.         show_framerate = !show_framerate;
  1216.         if (!show_framerate) reset_screens();
  1217.         break;
  1218.     default:
  1219.         break;
  1220.     }
  1221.     return 0;
  1222. }
  1223.  
  1224. static unsigned stype[] = { 
  1225.     0, 0x1000, 0x2000, 0x3000 };
  1226.  
  1227. unsigned paint = 1;
  1228. static unsigned surface = 0x1000;
  1229. static unsigned paintcolor = 1;
  1230.  
  1231. new_features()
  1232. {
  1233.     int x, y, c, i;
  1234.     unsigned buttons;
  1235.     char buff[100];
  1236.  
  1237.     if (!can_point_2D()) return 3;
  1238.  
  1239.     poptext(featmenu);
  1240.     reframe = 1;
  1241.     c = toupper(getkey());
  1242.     switch (c)
  1243.     {
  1244.     case 'S':/* select surface */
  1245.         poptext(surfmenu);
  1246.         reframe = 1;
  1247.         switch (toupper(getkey())) {
  1248.         case 'N':
  1249.             surface = stype[0];
  1250.             break;
  1251.         case 'C':
  1252.             surface = stype[1];
  1253.             break;
  1254.         case 'M':
  1255.             surface = stype[2];
  1256.             break;
  1257.         case 'G':
  1258.             surface = stype[3];
  1259.             break;
  1260.         }
  1261.         if (surface == 0)
  1262.             paint = paintcolor;
  1263.         else
  1264.             paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1265.         refresh_display();
  1266.         break;
  1267.  
  1268.     case 'C':/* select color */
  1269.         if (!manip_2D_avail) break;
  1270.         disp_palette();
  1271.         disp_palette();
  1272.         reframe = 1;
  1273.         do {
  1274.             move_till_click(cursor_device, 1, &x, &y);
  1275.         }
  1276.         while (y>128 || x>160);
  1277.         paintcolor = 16*(y/8) + x/10;
  1278.         if (surface == 0)
  1279.             paint = paintcolor;
  1280.         else
  1281.             paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1282.         refresh_display();
  1283.         break;
  1284.  
  1285.     case 'P':
  1286.         refresh_display();
  1287.         do {
  1288.             if (kbhit()) break;
  1289.             while (move_2D(cursor_device, &x, &y, &buttons) == 0 && !kbhit());
  1290.             if (buttons & 0x01) {
  1291.                 OBJECT *obj;
  1292.                 int poly;
  1293.                 obj = where_split_screen_pt(&poly, NULL, x, y);
  1294.                 if (obj) {
  1295.                     set_poly_color(obj, poly, paint);
  1296.                     refresh_display();
  1297.                 }
  1298.             }
  1299.         }
  1300.         while (!(buttons & 0x02));
  1301.         break;
  1302.     default:
  1303.         break;
  1304.     }
  1305.     return 0;
  1306. }
  1307.  
  1308.